<template>
    <!-- 更加props 的width 和height 来设置课程卡片的宽度和高度 -->
    <div class="courseCard" :style="{ width: (boxWidth < 200 ? '200px' : boxWidth + 'px') }">
        <div class="courseCardButton">
            <div class="editModeButton" v-if="editMode || deleteMode">
                <span class="deleteButton iconfont icon-likesprogramhuishouzhan" @click="deleteCourse"></span>
                <span class="defaultButton iconfont icon-likesprogrambianji" v-if="editMode" @click="editCourse"></span>
            </div>
            <div class="courseCardDefaultButton" v-else>
                <!-- 收藏按钮 -->
                <span class="defaultButton iconfont" :class="courseDetail?.collect? 'icon-likesprograma-shoucang2' : 'icon-likesprograma-shoucang'"
                    @click="collectCourse"></span>
            </div>
        </div>
        <!-- 前往课程详细页面 -->
        <router-link v-if="detailsUrl.length > 0" :to="`${detailsUrl}/${courseId}`"
            class="courseCardLink"></router-link>

        <div class="courseCardImage" v-if="mode === 'normal' || mode === 'image'">
            <img :src="baseUrl + courseDetail?.courseInfo?.coverPath" width="100%" alt="">
            <!-- 学生数量 和 评论数量 -->
            <div class="courseStudentAndComment">
                <span class="courseStudent information">
                    <span class="iconfont icon-likesprogramjiaoyu"></span>
                    {{ courseDetail?.courseFigures?.studentCount }}
                </span>
                <span class="courseComment information">
                    <span class="iconfont icon-likesprogramduihuakuang"></span>
                    {{ courseDetail?.courseFigures?.commentCount }}
                </span>
            </div>
        </div>
        <div class="courseCardContent" v-if="mode === 'normal' || mode === 'describe'">
            <div class="courseName" v-html="highlightText(courseDetail?.courseInfo?.courseName, searchStr, searchParticiple)"></div>
            <div class="courseDescription" v-html="highlightText(courseDetail?.courseInfo?.courseDescription, searchStr, searchParticiple)"></div>
            <div class="courseTeacherAndUpdateTime">
                <span class="courseTeacher">{{ courseDetail?.courseTeacher?.teacher.nickName }}</span>
                <span class="courseUpdateTime">{{ courseDetail?.courseFigures.updateTime }}</span>
            </div>
        </div>
        <!-- 消息对话框 -->
        <MessageDialog ref="messageDialog">
            <template v-slot:title>
                <span>{{ messageDialogData.title }}</span>
            </template>
            <template v-slot:content>
                <div class="dialogContent">
                    <div class="messageBox" :class="messageDialogData.type">
                        <div class="message" v-for=" message in messageDialogData.message">{{ message }}</div>
                    </div>
                </div>
            </template>
            <template v-slot:footer>
                <div class="dialogFooterButton" @click="closeMessage()">
                    <span class="line">取消</span>
                </div>
                <div class="dialogFooterButton" @click="closeMessage(true)">
                    <span>确认</span>
                </div>
            </template>
        </MessageDialog>
    </div>
</template>

<script lang="ts">
import { courseApi } from '@/api/course/Course';
import { defineComponent, ref, watch } from 'vue';
import { baseUrl } from '@/util/request';
import { CourseDetail } from '@/types/Course';
import { userApi } from '@/api/Users';
import { useRouter } from 'vue-router'

export default defineComponent({
    name: 'courseCard',
});
</script>

<script setup lang="ts">
    // 定义props
    const props = withDefaults(defineProps<{
        // 课程ID 必填
        courseId: number;
        searchParticiple?: string[]; // 搜索数据的分词
        searchStr?: string; // 搜索数据的分词
        // 显示模式 选填（默认为正常模式）normal/image/describe normal: 默认模式 显示图片和描述，describe: 显示描述，image: 显示图片
        mode?: string;
        // 编辑模式 选填（显示删除按钮和编辑按钮）
        editMode?: boolean;
        // 删除模式 选填（显示删除按钮）
        deleteMode?: boolean;
        // 课程详情页面的url 选填
        detailsUrl?: string;
        // 卡片宽度 选填
        boxWidth?: number;
    }>(), {
        courseId: 0,
        searchParticiple: () =>[],
        mode: 'normal',     // 默认为正常模式
        editMode: false,    // 默认不显示编辑按钮
        deleteMode: false,  // 默认不显示删除按钮
        detailsUrl: '',     // 默认路径为空
        boxWidth: 200,      // 默认宽度为200px
    });

    const router = useRouter();
    
    // 定义事件
    const emit = defineEmits<{
        // 删除事件
        (e: 'deleteEvent', courseId: number): void;
        // 编辑事件
        (e: 'editEvent', courseId: number): void;
        // 收藏事件
        (e: 'collectEvent', courseId: number): void;
    }>();
    
    // 消息对话框
    const messageDialog = ref(null);
    const messageDialogData = ref({
        title: '',
        message: [''],
        type: 'success',
    });
    const showMessage = (title: string, message: string[], type: string) => {
        messageDialogData.value = {title, message, type};
        messageDialog.value.ShowModal();
    }
    const closeMessage = async (confirm?:boolean) => {
        messageDialog.value.Close();
        if (confirm === true && await userApi.isTokenExpired().then(res => res).catch(error => true)) {
            router.push({ name: 'login'});
        }
    }
    
    // 响应式变量
    const courseDetail = ref<CourseDetail>(null);
    
    // 获取课程信息
    const getCourseInfo = (courseId: number) => {
        courseApi.findCourseInfo(courseId).then(res => {
            courseDetail.value = res;
        })
    };
    
    // 触发删除事件
    const deleteCourse = () => {
        emit('deleteEvent', props.courseId);
    };
    
    // 触发编辑事件
    const editCourse = () => {
        emit('editEvent', props.courseId);
    };
    
    // 触发收藏事件
    const collectCourse = async () => {
        try {
            const userRes = await userApi.isTokenExpired().then(res => res).catch(error => true);
            if (userRes) {
                showMessage("收藏课程", ["请先登录，是否现在前往登录"], "success");
                return false;
            }
            let res;
            if (courseDetail.value.collect) {
                res = await courseApi.cancelCollectCourse(props.courseId);
            } else {
                res = await courseApi.collectCourse(props.courseId);
            }
            if (res.code === 200) {
                courseDetail.value.collect = !courseDetail.value.collect;
                return true;
            }
            showMessage("收藏课程", [res.message], "failure");
            return false;
        } catch (error) {
            showMessage("收藏课程", ["收藏课程失败"], "failure");
            return false;
        }
        emit('collectEvent', props.courseId);
    };
    
    // yang-chai-lang: 课程卡片
    watch(() => props.courseId, (newValue) => {
        // 获取课程信息
        getCourseInfo(newValue);
    }, { immediate: true, deep: true });
    
    // 将文本中包含的搜索分词高亮显示
    function highlightText(text: string, searchStr: string, searchParticiple: string[]): string {
        if (!text) return ''
        
        console.log('highlightText', text, searchStr, searchParticiple)
        
        const parser = new DOMParser()
        const doc = parser.parseFromString(`<div>${text}</div>`, 'text/html')
        
        const wordsSet = new Set<string>()
        
        // 优先放入 searchStr
        if (searchStr?.trim()) {
          wordsSet.add(searchStr.trim())
        }
    
        // 再放入 searchParticiple，且剔除已包含在 searchStr 里的词
        if (searchParticiple && searchParticiple.length > 0) {
          for (const word of searchParticiple) {
            if (word.trim() && !wordsSet.has(word)) {
              wordsSet.add(word)
            }
          }
        }
    
        const safeWords = Array.from(wordsSet)
          .filter(Boolean)
          .sort((a, b) => b.length - a.length) // 长的优先匹配，防止短词破坏长词
          .map(word => {
            const safeWord = word.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1')
            return {
              word,
              regex: new RegExp(safeWord, 'gi'),
            }
          })
      
        const walk = (node: Node) => {
          if (node.nodeType === Node.TEXT_NODE) {
            const textNode = node as Text
            const parent = textNode.parentElement
            
            // 父节点是高亮则不处理
            if (parent?.classList.contains('highlightText')) return
            
            let content = textNode.nodeValue || ''
            
            // 提前判断：如果父节点已经是highlight，不处理
            if (!content.trim()) return
            
            // 遍历所有关键字
            let replaced = false
            for (const { regex } of safeWords) {
              if (regex.test(content)) {
                content = content.replace(regex, (match) => `<span class="highlightText">${match}</span>`)
                replaced = true
                break
              }
            }
        
            if (replaced) {
              const temp = document.createElement('div')
              temp.innerHTML = content
              const frag = document.createDocumentFragment()
              Array.from(temp.childNodes).forEach(child => frag.appendChild(child))
              textNode.parentNode?.replaceChild(frag, textNode)
            }
          } else {
            node.childNodes.forEach(walk)
          }
        }
    
        walk(doc.body)
    
        return doc.body.innerHTML
    }
</script>

<style src="@/assets/icons/iconfont.css" scoped></style>

<style scoped>
.courseCard {
    padding: 0;
    border-radius: 10px;
    overflow: hidden;
    position: relative;
    background-color: rgba(255, 255, 255, .5);
    backdrop-filter: blur(2rem);
    -webkit-backdrop-filter: blur(2rem);
    -moz-backdrop-filter: blur(2rem);
    -ms-backdrop-filter: blur(2rem);
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}

.courseCard .courseCardButton {
    position: absolute;
    z-index: 2;
    top: 10px;
    right: 10px;
    overflow: hidden;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

.courseCard .courseCardButton .editModeButton {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

.courseCard .courseCardButton .courseCardDefaultButton {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

.courseCard .courseCardButton .iconfont {
    width: 38px;
    height: 38px;
    font-size: 20px;
    margin-left: 10px;
    border-radius: 5px;
    display: inline-block;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all .3s;
    background-color: antiquewhite;
}

.courseCard .courseCardButton .iconfont:hover {
    font-size: 24px;
}

.courseCard .courseCardButton .iconfont:active {
    font-size: 20px;
    transition: all .1s;
}

.courseCard .courseCardButton .deleteButton {
    background-color: rgba(221, 0, 0, 1);
    color: #fff;
}

.courseCard .courseCardButton .defaultButton {
    background-color: rgba(65, 185, 255, 1);
    color: #fff;
}

.courseCard .courseCardLink {
    position: absolute;
    display: block;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
}

.courseCard .courseCardImage {
    position: relative;
}

.courseCard .courseCardImage img {
    max-width: 300px;
    max-height: 150px;
    display: block;
}

.courseCard .courseCardImage .courseStudentAndComment {
    position: absolute;
    bottom: 0px;
    width: 100%;
    height: 38px;
    padding: 0px 10px;
    background-image: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .8) 100%);
    color: #fff;
    display: flex;
    justify-content: flex-start;
    align-items: center;
}

.courseCard .courseCardImage .courseStudentAndComment .information {
    font-size: 14px;
    margin-right: 15px;
}

.courseCard .courseCardImage .courseStudentAndComment .iconfont {
    font-size: 16px;
}


.courseCard .courseCardContent {
    padding: 0px 10px;
}

.courseCard .courseCardContent .courseName {
    font-size: 16px;
    padding: 8px 0px;
    font-weight: bold;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.courseCard .courseCardContent .courseDescription {
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    line-clamp: 2;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    min-height: 42px;
}

:deep(.highlightText) {
    padding: 0px 2px;
    color: rgb(0, 162, 255);
}

.courseCard .courseCardContent .courseTeacherAndUpdateTime {
    font-size: 12px;
    padding: 8px 0px;
    padding-bottom: 10px;
    color: rgba(100, 100, 100, 1);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.courseCard .courseCardContent .courseTeacherAndUpdateTime .courseTeacher {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.courseCard .courseCardContent .courseTeacherAndUpdateTime .courseUpdateTime {
    padding-top: 3px;
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 对话框底部按钮 */
.dialogFooterButton {
    width: 100%;
    height: 65px;
    position: relative;
    display: flex;
    color: rgba(65, 185, 255, 1);
    justify-content: center;
    align-items: center;
    cursor: pointer;
    transition: .3s all;
}
.dialogFooterButton:hover {
    background-color: rgba(200, 200, 200, .15);
}
.dialogFooterButton:active {
    transition: .1s all;
    background-color: rgba(220, 220, 220, .1);
}
.dialogFooterButton .line {
    width: 100%;
    border-right: 1px solid rgba(200, 200, 200, 1);
    display: flex;
    justify-content: center;
    align-items: center;
}
.messageBox {
    padding: 10px;
}
.messageBox.success {
    color: rgba(65, 185, 255, 1);
}
.messageBox.failure {
    color: rgba(255, 0, 0, 1);
}
</style>